package parsing.yago;

import java.util.ArrayList;
import java.util.TreeMap;

import core.objects.Book;
import core.objects.Category;
import core.objects.City;
import core.objects.Country;
import core.objects.Publisher;
import core.objects.Author;


class TransitiveTypeParser extends YagoFileParser {
		
	private static final String TRANSITIVE_TYPE = "yagoTransitiveType.tsv";
	private static final int ESTIMATED_LINES_NUM = 43500000;
	
	private static final String YAGO_RDF_TYPE = "rdf:type";
	private static final String WORDNET_BOOK = "wordnet book 106410904";
	private static final String WORDNET_NOVEL = "wordnet novel 106367879";
	private static final String WORDNET_NOVELIST = "wordnet novelist 110363573";
	private static final String WORDNET_WRITER = "wordnet writer 11079014";
	private static final String WORDNET_CITY = "wordnet city 108524735";
	private static final String WORDNET_TOWN = "wordnet town 108665504";
	private static final String WORDNET_VILLAGE = "wordnet village 108672562";	
	private static final String WORDNET_REGION = "wordnet village 108630985";
	
	/* YAGO is a weird beast. For some reason, not all novelists and
	 * writers come with the appropriate tag. Therefore, we will
	 * also search for writers who appear as authors of books in
	 * categories (rather than as simply authors). Not to worry
	 * about duplicates, we will remove them. We shall tame this lion!*/
	private static final String WIKICATEGORY_BOOKS_BY = "Books by";
	private static final String WIKICATEGORY_NOVELS_BY = "Novels by";
	
	/* for some reason, wordnet_country_? is littered with needless
	 * data, so for countries we will only select those who are
	 * tagged as members of the UN (best filter we could find) */
	private static final String WIKICATEGORY_UN_COUNTRY = "wikicategory Member states of the United Nations";
	
	/* Objects in YAGO appear consecutively, however we may only
	 * find them to be books after we've read their categories.
	 * Since TransitiveTypes is a big file (> 43M records),
	 * we'd like to avoid reading it over. That's why we'll
	 * maintain a list of categories when relevant and should
	 * the object we're scanning be found a book / novel,
	 * we'll add the categories we've found to that object.  */
	private ArrayList<Category> bookCategories = null;
	private String currentRecord = null;
	
	TransitiveTypeParser(String directory) {
		super(directory);
	}
	
	@Override
	protected String getFileName() {
		return TRANSITIVE_TYPE;
	}
	
	@Override
	protected int getEstimatedFileLinesNumber() {
		return ESTIMATED_LINES_NUM;
	}

	@Override
	protected void handleLineParsing(final String[] line) {
		
		/* line is "<something> rdf:type <what_that_something_is>"*/
		
		if (currentRecord == null || !currentRecord.equals(line[0])) {
			currentRecord = line[0];
			bookCategories = new ArrayList<Category>();
		}
		
		if (line[2].equals(WORDNET_BOOK) || line[2].equals(WORDNET_NOVEL)) {
			Book book = new Book(0, line[0]);
			ParsingEnvironment.getBooks().put(line[0], book);
			if (bookCategories.size() > 0) {
				for (Category c : bookCategories) {
					book.addCategory(c);
				}
				bookCategories.clear();
			}
		} else if (line[2].equals(WIKICATEGORY_UN_COUNTRY)) {
			ParsingEnvironment.getCountries().put(line[0], new Country(0, line[0]));			
		} else if (line[2].equals(WORDNET_CITY) || line[2].equals(WORDNET_TOWN)
				|| line[2].equals(WORDNET_VILLAGE) || line[2].equals(WORDNET_REGION)) {
			ParsingEnvironment.getCities().put(line[0], new City(0, line[0]));
		} else if (line[2].equals(WORDNET_WRITER) || line[2].equals(WORDNET_NOVELIST) ||
				(line[2].startsWith(WIKICATEGORY) &&
						(removeWikicategory(line[2]).startsWith(WIKICATEGORY_BOOKS_BY) ||
								removeWikicategory(line[2]).startsWith(WIKICATEGORY_NOVELS_BY)))) {
			
			TreeMap<String, Author> writers = ParsingEnvironment.getWriters();
			if (line[2].startsWith(WIKICATEGORY)) {
				String writer = removeWikicategory(line[2]);
				writer = writer.replace(WIKICATEGORY_BOOKS_BY, "").trim();
				writer = writer.replace(WIKICATEGORY_NOVELS_BY, "").trim();
				writers.put(writer, new Author(0, writer));
			} else {
				writers.put(line[0], new Author(0, line[0]));
			}
		} else if (line[2].startsWith(WIKICATEGORY) && ParsingEnvironment.getCategories().containsKey(removeWikicategory(line[2]))) {
			Book book = ParsingEnvironment.getBooks().get(line[0]);
			if (book != null) {
				book.addCategory(ParsingEnvironment.getCategories().get(removeWikicategory(line[2])));
			} else {
				bookCategories.add(ParsingEnvironment.getCategories().get(removeWikicategory(line[2])));
			}
		} else if (line[2].startsWith(WIKICATEGORY) && ParsingEnvironment.getPublisherCategories().containsKey(removeWikicategory(line[2]))) {
			ParsingEnvironment.getPublishers().put(line[0], new Publisher(0, line[0]));			
		}
		
	}
	
	@Override
	protected boolean isLineFromFileOkay(String[] line) {
		/* line should be "<..> rdf:type <..>" */
		return line.length == 3 && line[1].equals(YAGO_RDF_TYPE);
	}

}
